from django.core.exceptions import ValidationError
from django.shortcuts import render, redirect
from .models import Book, Author, BookInstance, Genre
from django.views.generic import DetailView, ListView
from django.views import View
from django.contrib.auth import login, logout, authenticate
from django.contrib import messages
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.views.generic import TemplateView


def index(request):
    """网站主页的视图函数"""
    # 生成统计数据
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()
    num_authors = Author.objects.count()
    num_genres = Genre.objects.count()

    # 记录访问次数（通过session）
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1

    # 获取最近添加的5本书
    recent_books = Book.objects.order_by('-id')[:5]


    # 传递数据到模板
    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
        'num_genres': num_genres,
        'num_visits': num_visits,
        'recent_books': recent_books,
    }
    return render(request, 'catalog/index.html', context=context)


class BookDetailView(DetailView):
    model = Book
    template_name = 'catalog/book_detail.html'
    context_object_name = 'book'


class BookListView(ListView):
    model = Book
    paginate_by = 6


class AuthorListView(ListView):
    model = Author
    paginate_by = 6


class AuthorDetailView(DetailView):
    model = Author

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['author_books'] = Book.objects.filter(author=self.object)
        return context


class UserLoginView(View):
    def get(self, request):
        return render(request, 'catalog/login.html')

    def post(self, request):
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            messages.success(request, f"欢迎回来，{username}！")
            return redirect(reverse('index'))
        else:
            messages.error(request, "用户名或密码错误")
            return render(request, 'catalog/login.html')


class UserLogoutView(View):
    def get(self, request):
        logout(request)
        messages.success(request, "您已成功登出！")
        return render(request, 'catalog/logout_confirm.html')


class UserRegisterView(View):
    def get(self, request):
        from django.contrib.auth.forms import UserCreationForm
        form = UserCreationForm()
        return render(request, 'catalog/register.html', {'form': form})

    def post(self, request):
        from django.contrib.auth.forms import UserCreationForm
        form = UserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            messages.success(request, "注册成功！欢迎使用本地图书馆")
            return redirect(reverse('index'))
        messages.error(request, "注册失败，请检查输入")
        return render(request, 'catalog/register.html', {'form': form})


@login_required
def user_profile(request):
    return render(request, 'catalog/profile.html')


class StaffOnlyView(TemplateView):
    template_name = 'catalog/staff_only.html'
    login_url = 'user-login'

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_staff:
            return redirect(reverse('index'))
        return super().dispatch(request, *args, **kwargs)


from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import BookInstance


class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView):
    """仅显示当前用户借阅的图书"""
    model = BookInstance
    template_name = 'catalog/bookinstance_list_borrowed_by_user.html'
    paginate_by = 10  # 每页显示10条记录

    def get_queryset(self):
        """返回当前用户借阅的状态为'已借出'的图书"""
        return BookInstance.objects.filter(
            borrower=self.request.user,
            status__exact='o'
        ).order_by('due_back')  # 按归还日期排序


from django.views.generic.edit import FormView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from .forms import RenewBookForm, AuthorForm
from .models import BookInstance


from django.contrib import messages

@method_decorator(login_required, name='dispatch')
class RenewBookView(FormView):
    form_class = RenewBookForm
    template_name = 'catalog/book_renew.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['bookinstance_id'] = self.kwargs['pk']
        return kwargs

    def form_valid(self, form):
        book_instance = get_object_or_404(BookInstance, pk=self.kwargs['pk'])

        # 检查当前用户是否是借阅者或管理员
        if self.request.user != book_instance.borrower and not self.request.user.is_staff:
            messages.error(self.request, "你没有权限续借此书")
            return redirect('my-borrowed')

        # 更新续借日期
        book_instance.due_back = form.cleaned_data['renewal_date']
        book_instance.save()

        messages.success(self.request, "续借成功！新的归还日期为：{}".format(book_instance.due_back))
        return redirect(reverse('my-borrowed'))


from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .models import Author


class AuthorCreateView(LoginRequiredMixin, CreateView):
    """创建新作者的视图"""
    model = Author
    form_class = AuthorForm
    template_name = 'catalog/author_form.html'

    def test_func(self):
        """只有管理员可创建作者"""
        return self.request.user.is_staff


class AuthorUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    """更新作者的视图"""
    model = Author
    form_class = AuthorForm
    template_name = 'catalog/author_form.html'

    def test_func(self):
        """只有管理员可更新作者"""
        return self.request.user.is_staff


class AuthorDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    """删除作者的视图"""
    model = Author
    template_name = 'catalog/author_confirm_delete.html'
    success_url = reverse_lazy('authors')

    def test_func(self):
        """只有管理员可删除作者，且作者无关联书籍"""
        author = self.get_object()
        if author.book_set.exists():
            raise ValidationError("该作者有关联书籍，不能删除")
        return self.request.user.is_staff


from django.shortcuts import get_object_or_404, redirect
from django.views.generic.edit import FormView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from .models import BookInstance
from django.utils import timezone


@method_decorator(login_required, name='dispatch')
class BorrowBookView(View):
    def get(self, request, pk):
        book_instance = get_object_or_404(BookInstance, pk=pk)

        # 检查书籍是否可借阅
        if book_instance.status != 'a':
            messages.error(request, "此书当前不可借阅")
            return redirect('book-detail', pk=book_instance.book.pk)

        # 更新借阅状态
        book_instance.status = 'o'
        book_instance.borrower = request.user
        book_instance.due_back = timezone.now().date() + timezone.timedelta(weeks=3)
        book_instance.save()

        messages.success(request, "借阅成功！应归还日期：{}".format(book_instance.due_back))
        return redirect('book-detail', pk=book_instance.book.pk)


from django.views.generic.edit import FormView
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from .forms import RenewBookForm
from .models import BookInstance
from django.utils import timezone


@method_decorator(login_required, name='dispatch')
class RenewBookView(FormView):
    form_class = RenewBookForm
    template_name = 'catalog/book_renew.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['bookinstance_id'] = self.kwargs['pk']
        return kwargs

    def form_valid(self, form):
        book_instance = get_object_or_404(BookInstance, pk=self.kwargs['pk'])

        # 检查当前用户是否是借阅者或管理员
        if self.request.user != book_instance.borrower and not self.request.user.is_staff:
            return redirect('my-borrowed')

        # 更新续借日期
        book_instance.due_back = form.cleaned_data['renewal_date']
        book_instance.save()

        return redirect(reverse('my-borrowed'))


from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import get_object_or_404, redirect
from django.contrib import messages
from .models import BookInstance


class ReturnBookView(PermissionRequiredMixin, View):
    permission_required = 'catalog.can_mark_returned'

    def get(self, request, pk):
        book_instance = get_object_or_404(BookInstance, pk=pk)

        # 检查书籍是否已借出
        if book_instance.status != 'o':
            messages.error(request, "这本书当前未被借出")
            return redirect('book-detail', pk=book_instance.book.pk)

        # 更新书籍状态
        book_instance.status = 'a'
        book_instance.borrower = None
        book_instance.due_back = None
        book_instance.save()

        messages.success(request, "书籍已成功归还")
        return redirect('book-detail', pk=book_instance.book.pk)